﻿Public Class FrmMain

    Dim WithEvents Puzzle As Puzzle
    Dim Game As String

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Me.Load
        MnuSolve.Image = MnuSolve.Image.Resize(16, 16, 2)
        BtnSolve.Image = BtnSolve.Image.Resize(16, 16, 2)
        MnuPause.Image = MnuPause.Image.Resize(16, 16, 2)
        BtnPause.Image = BtnPause.Image.Resize(16, 16, 2)
        MnuStop.Image = MnuStop.Image.Resize(16, 16, 2)
        BtnStop.Image = BtnStop.Image.Resize(16, 16, 2)
        ToolStrip1.Renderer = New Renderer
        MenuStrip1.Renderer = New Renderer
        ToolStripContainer1.TopToolStripPanel.Renderer = New Renderer
        Game = GetSetting("PuzzleStudio", "Startup", "Game", "Sudoku")
        If Type.GetType("PuzzleStudio." & Game) Is Nothing Then Game = "Sudoku"
        NewGame()
    End Sub

    Sub AdjustButtons()
        MnuExpand.Enabled = Puzzle.SupportsSizing
        MnuShrink.Enabled = Puzzle.SupportsSizing
        BtnExpand.Enabled = Puzzle.SupportsSizing
        BtnShrink.Enabled = Puzzle.SupportsSizing
        MnuMakeGroup.Enabled = Puzzle.SupportsRegioning
        BtnMakeGroup.Enabled = Puzzle.SupportsRegioning
        MnuDeleteGroup.Enabled = Puzzle.SupportsRegioning
    End Sub

    Protected Overrides Function ProcessCmdKey(ByRef msg As System.Windows.Forms.Message, ByVal keyData As System.Windows.Forms.Keys) As Boolean
        Dim Result As Boolean
        Select Case keyData
            Case Keys.Up : Result = Puzzle.OnKeyPress("up")
            Case Keys.Down : Result = Puzzle.OnKeyPress("down")
            Case Keys.Left : Result = Puzzle.OnKeyPress("left")
            Case Keys.Right : Result = Puzzle.OnKeyPress("right")
            Case Keys.Control + Keys.Up : Result = Puzzle.OnKeyPress("^up")
            Case Keys.Control + Keys.Down : Result = Puzzle.OnKeyPress("^down")
            Case Keys.Control + Keys.Left : Result = Puzzle.OnKeyPress("^left")
            Case Keys.Control + Keys.Right : Result = Puzzle.OnKeyPress("^right")
            Case Keys.Home : Result = Puzzle.OnKeyPress("home")
            Case Keys.End : Result = Puzzle.OnKeyPress("end")
            Case Keys.Delete : Result = Puzzle.OnKeyPress("delete")
            Case Keys.Back : Result = Puzzle.OnKeyPress("back")
        End Select
        If Result Then Return True
        Return MyBase.ProcessCmdKey(msg, keyData)
    End Function

    Private Sub NewGame()
        If Not Puzzle Is Nothing Then
            Puzzle.Board = Nothing
            Puzzle = Nothing
        End If
        Puzzle = Activator.CreateInstance(Type.GetType("PuzzleStudio." & Game.Replace(" ", ""), True, True))
        Puzzle.Board = Board
        Puzzle.SetAutosolve(True)
        Text = "Unsaved puzzle - " & TypeName(Puzzle)
        Puzzle.NewPuzzle()
        AdjustButtons()
        Board.Invalidate()
        Board.Focus()
    End Sub

    Private Sub Puzzle_LogAdd(ByVal Text As String) Handles Puzzle.LogAdd
        If Text = "<clr>" Then
            TextBox1.Text = ""
        Else
            TextBox1.AppendText(Text)
        End If
    End Sub

    Private Sub SavePuzzle(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MnuSave.Click, BtnSave.Click
        If Puzzle.Title = "" Then MnuSaveas.PerformClick() : Exit Sub
        Dim Doc As New Xml.XmlTextWriter(Puzzle.Title, System.Text.Encoding.Default)
        Doc.WriteStartDocument()
        Doc.WriteStartElement("Game")
        Puzzle.SavePuzzle(Doc)
        Doc.WriteEndElement()
        Doc.WriteEndDocument()
        Doc.Close()
        Puzzle.Invalidate()
    End Sub

    Sub ShowSaveDialog()
        Dim Dialog As New SaveFileDialog
        Dialog.DefaultExt = "pzl"
        Dialog.Filter = "Puzzle studio oyunları (*.pzl)|*.pzl|Tüm dosyalar (*.*)|*.*"
        If Dialog.ShowDialog = Windows.Forms.DialogResult.Cancel Then Exit Sub
        Puzzle.Title = Dialog.FileName
        Me.Text = Puzzle.Title & " - " & TypeName(Puzzle)
    End Sub

    Private Sub SavePuzzleAs(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MnuSaveas.Click
        ShowSaveDialog()
        If Puzzle.Title = "" Then Exit Sub
        MnuSave.PerformClick()
    End Sub

    Private Sub OpenPuzzle(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MnuOpen.Click, BtnOpen.Click
        Dim Dialog As New OpenFileDialog
        Dialog.DefaultExt = "pzl"
        Dialog.Filter = "Oyun dosyaları (*.pzl, *.sdk)|*.pzl;*.sdk|Sudoku dosyaları (*.sdk)|*.sdk|Tüm dosyalar (*.*)|*.*"
        If Dialog.ShowDialog = Windows.Forms.DialogResult.Cancel Then Exit Sub
        Try
            Dim Doc As New Xml.XmlDocument
            Doc.Load(Dialog.FileName)
            Game = Doc.SelectSingleNode("Game").SelectSingleNode("Name").InnerText
            NewGame()
            Puzzle.LoadPuzzle(Doc.SelectSingleNode("Game"))
        Catch ex As Exception
            Dim Text As String = My.Computer.FileSystem.ReadAllText(Dialog.FileName, System.Text.Encoding.ASCII)
            If LCase(Dialog.FileName).EndsWith(".sdk") Then
                Game = "Sudoku"
                NewGame()
                Puzzle.Load(Text.Replace(".", " ").Replace(vbCrLf, ""))
            Else
                Dim Pos As Integer = InStr(Text, ";")
                Game = Mid(Text, 1, Pos - 1)
                NewGame()
                Puzzle.Load(Mid(Text, Pos + 1))
            End If
        End Try
        Puzzle.Title = Dialog.FileName
        Me.Text = Dialog.FileName & " - " & TypeName(Puzzle)
    End Sub

    Private Sub SolvePuzzle(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MnuSolve.Click, BtnSolve.Click
        Puzzle.Solve()
    End Sub

    Private Sub MnuExit_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MnuExit.Click
        Close()
    End Sub

    Private Sub NewPuzzle(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MnuNew.Click, BtnNew.Click
        NewGame()
    End Sub

    Private Sub CopyPuzzle(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MnuCopy.Click
        Puzzle.Edit("copy")
    End Sub

    Private Sub MnuPaste_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MnuPaste.Click
        If Clipboard.ContainsImage Then
            Dim Image = Clipboard.GetImage
            Dim M = ProcessImage(Image)
            Puzzle.SetHintsFromMatrix(M)
            Exit Sub
        End If

        Puzzle.Edit("paste")
    End Sub

    Private Sub MnuClear_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MnuClear.Click
        Puzzle.Edit("clear")
    End Sub

    Private Sub MnuAutosolve_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MnuAutosolve.Click
        MnuAutosolve.Checked = Not MnuAutosolve.Checked
        Puzzle.SetAutosolve(MnuAutosolve.Checked)
    End Sub

    Private Sub MnuMode_DropDownItemClicked(ByVal sender As Object, ByVal e As System.Windows.Forms.ToolStripItemClickedEventArgs) Handles MnuMode.DropDownItemClicked
        Game = e.ClickedItem.Name.Substring(3)
        SaveSetting("PuzzleStudio", "Startup", "Game", Game)
        NewGame()
    End Sub

    Private Sub MnuMakeGroup_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MnuMakeGroup.Click, BtnMakeGroup.Click
        Puzzle.Edit("make group")
    End Sub

    Private Sub MnuExpand_Click(sender As System.Object, e As System.EventArgs) Handles MnuExpand.Click, BtnExpand.Click
        Puzzle.Edit("expand")
    End Sub

    Private Sub MnuShrink_Click(sender As System.Object, e As System.EventArgs) Handles MnuShrink.Click, BtnShrink.Click
        Puzzle.Edit("shrink")
    End Sub

    Private Sub MnuMark_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MnuMark.Click
        Puzzle.Edit("mark")
    End Sub

    Private Sub FrmMain_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.TextChanged
        Board.Invalidate()
    End Sub

    Private Sub Board_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles Board.KeyPress
        e.Handled = Puzzle.OnKeyPress(e.KeyChar)
    End Sub

    Private Sub Undo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BtnUndo.Click, MnuUndo.Click
        Puzzle.Undo()
    End Sub

    Private Sub Redo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BtnRedo.Click, MnuRedo.Click
        Puzzle.Redo()
    End Sub

    Private Sub MnuRotate1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MnuRotate1.Click, MnuRotate2.Click
        Puzzle.Edit("rotate " & Choose(Strings.Right(sender.Name, 1), "left", "right"))
    End Sub

    Function ProcessImage(ByVal Image As Bitmap)
        Dim Size = 9
        Dim M(Size, Size)
        Dim w = Image.Width / Size
        Dim h = Image.Height / Size
        For Each res In From x In Range(1, Size) From y In Range(1, Size)
            Dim R As New Rectangle((res.x - 1) * w, (res.y - 1) * h, w, h)
            M(res.x, res.y) = ScanHint(Image, R)
        Next
        Return M
    End Function

    Function ScanHint(ByVal Image As Bitmap, ByVal R As Rectangle) As String
        Dim B As New Bitmap(32, 32)
        Dim G As Graphics = Graphics.FromImage(B)
        G.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic
        R.Inflate(-4, -4)
        G.DrawImage(Image, New Rectangle(0, 0, B.Width, B.Height), R, GraphicsUnit.Pixel)
        'showimage(B)
        B = CropImage(B)
        'showimage(B)
        Dim Min = (From ch In Chars Let d = ImageDiff(B, ch.Value) Order By d).First
        If Min.d > 20000 Then Return ""
        Return Min.ch.Key
        'Dim OCR As New MODI.Document
        'Dim File = My.Computer.FileSystem.SpecialDirectories.Temp & "\ocr.png"
        'Image.Save(File)
        'OCR.Create(File)
        'OCR.OCR(MODI.MiLANGUAGES.miLANG_ENGLISH, True, True)
        'For Each insImage In OCR.Images
        '    Dim insLayout As MODI.Layout = insImage.Layout
        '    MsgBox(insLayout.Text)
        'Next
        'OCR.Close(False)

    End Function

    Function ImageDiff(ByVal B1 As Bitmap, ByVal B2 As Bitmap) As Integer
        Dim d As Double = 0
        'showimage(B1, B2)
        For x = 0 To 15
            For y = 0 To 15
                Dim c1 = B1.GetPixel(x, y)
                Dim c2 = B2.GetPixel(x, y)
                d += Math.Abs(CDbl(c1.R) - CDbl(c2.R))
            Next
        Next
        'If d > 0 Then Stop
        Return d
    End Function

    ReadOnly Property Chars As SortedList(Of String, Bitmap)
        Get
            Static List As New SortedList(Of String, Bitmap)
            If List.Count = 0 Then
                For Each ch In Split("1,2,3,4,5,6,7,8,9", ",")
                    Dim B As New Bitmap(64, 64)
                    Dim G As Graphics = Graphics.FromImage(B)
                    G.Clear(Color.White)
                    G.TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAliasGridFit
                    Dim R As New Rectangle(0, 0, B.Width, B.Height)
                    TextRenderer.DrawText(G, ch, New Font("arial", B.Height / 2), R, Color.Black, Color.White, TextFormatFlags.HorizontalCenter + TextFormatFlags.VerticalCenter)
                    B = CropImage(B)
                    List.Add(Trim(ch), B)
                Next
            End If
            Return List
        End Get
    End Property

    Sub showimage(ByVal B As Bitmap)
        Dim f As New Form
        f.StartPosition = FormStartPosition.CenterScreen
        f.BackgroundImage = B
        f.BackgroundImageLayout = ImageLayout.Stretch
        AddHandler f.Click, AddressOf f.Close
        f.ShowDialog()
    End Sub

    Sub showimage(ByVal B1 As Bitmap, ByVal B2 As Bitmap)
        Dim B As New Bitmap(16, 16)
        Dim G As Graphics = Graphics.FromImage(B)
        G.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic
        G.DrawImageWithOpacity(B1, New Rectangle(0, 0, B.Width, B.Height), 0.5)
        G.DrawImageWithOpacity(B2, New Rectangle(0, 0, B.Width, B.Height), 0.5)
        showimage(B)
    End Sub

    Function CropImage(ByVal B As Bitmap) As Bitmap
        For x = 0 To B.Width - 1
            For y = 0 To B.Height - 1
                Dim r = B.GetPixel(x, y).R
                If r < 128 Then r = 0 Else r = 255
                B.SetPixel(x, y, Color.FromArgb(r, r, r))
            Next
        Next
        Dim xx = (From x In Range(0, B.Width - 1) Where (From y In Range(0, B.Height - 1) Where B.GetPixel(x, y).R < 128).Count > 1)
        Dim yy = (From y In Range(0, B.Height - 1) Where (From x In Range(0, B.Width - 1) Where B.GetPixel(x, y).R < 128).Count > 1)
        Dim Bm As New Bitmap(32, 32)
        If xx.Count = 0 Or yy.Count = 0 Then Return Bm
        Dim G As Graphics = Graphics.FromImage(Bm)
        G.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic
        Dim RR As New Rectangle(xx.First, yy.First, xx.Last - xx.First, yy.Last - yy.First)
        RR.Inflate((RR.Height - RR.Width) / 2, 0)
        G.DrawImage(B, New Rectangle(0, 0, 32, 32), RR, GraphicsUnit.Pixel)
        showimage(Bm)
        Return Bm
    End Function
End Class

